feat(aux-audit): score agent-spec v1 — authority, not labels (0.2.0) - #14
Merged
Conversation
Closes the last half of #10. aux.H01 and aux.H03 stop asking "what did you call your autonomy level" and start asking what a v1 spec actually declares: per-action authority, the mechanism enforcing each row, and the five forms of human control. Architecture: both versions normalise into one evidence model (src/evidence.ts) that the rules read. One rule set instead of two, and the difference between what v0 and v1 can express becomes a visible, tested mapping rather than branching scattered through the rules. Where a version cannot express something, the field is absent and the rule says so — it never scores absence of a *field* as absence of a *mechanism*. What v1 makes computable that v0 could not: - aux.H05 reports the gap between what the credentials permit and what the mandate governs. The schema calls that the attack surface; it is now a number with the ungoverned capabilities named. - a row enforced by "the system prompt" is reported as unenforced, per trust-architecture: a prompt is a request, a tool boundary is a control. - aux.H04 reads consequence_scaled_approval and whether authority varies across actions at all — a single authority for every action is the slider the canon rejects, wearing a table. - aux.H07 requires an escalation to name both a recipient and what happens on timeout, because without on_timeout "ask a human" is a queue that fills up. Two findings that changed the design: 1. v1 has no memory field. Not "memory: false" — no field. aux.H08 is therefore reported as not scoreable rather than scored zero, and a quarter of the taxonomy (memory_amnesia, preference_ignored, context_leak) is unreachable from a v1 spec. Worth fixing in the schema; noted in #10. 2. A trust stage backed only by an unscoreable heuristic was being reported as EARNED. aux.T02 Contextual Trust depends solely on aux.H08, so every v1 spec was silently earning contextual trust on zero evidence — a claim dressed as a finding, which is the exact failure this taxonomy exists to name. Stages now carry `assessable`, an unassessable stage is never earned, and it stops the ladder the way a broken one does. Two regression tests pin it. v0.1.0 scoring is unchanged: same fixtures, same scores, same evidence strings. meta.spec_version records which format produced a report, since scores are not comparable across the two. 48 tests, up from 38. ajv added for real draft 2020-12 validation, with `format: date` implemented rather than ignored. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MhpqWEvwKp7NrmJfdXYq4M
14 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Closes the last half of #10.
aux.H01andaux.H03stop asking "what did you call your autonomy level" and start asking what a v1 spec actually declares: per-action authority, the mechanism enforcing each row, and the five forms of human control.Both spec versions are scored, detected from the document rather than the filename.
Architecture
Both versions normalise into one evidence model (
src/evidence.ts) that the rules read. One rule set instead of two, and the difference between what v0 and v1 can express becomes a visible, tested mapping rather than branching scattered through the rules.Where a version cannot express something, the field is absent and the rule says so. It never scores absence of a field as absence of a mechanism.
What v1 makes computable that v0 could not
aux.H05reports the capability/mandate gap. The schema header calls it the attack surface; it is now a number with the ungoverned capabilities named. On the weak fixture: "2 capabilities the credentials grant but no mandate governs: delete_email, calendar_event".trust-architecture.yaml: a prompt is a request, a tool boundary is a control.aux.H04readsconsequence_scaled_approvaland whether authority varies across actions at all. A single authority for every action is the slider the canon rejects, wearing a table.aux.H07requires an escalation to name both a recipient andon_timeout, because without it "ask a human" is a queue that fills up.Two findings that changed the design
1. v1 has no memory field. Not
memory: false— no field at all.aux.H08is therefore reported as not scoreable rather than scored zero. A consequence worth stating plainly: three of the twelve taxonomy gaps (memory_amnesia,preference_ignored,context_leak) are unreachable from a v1 spec. That is a coverage regression in the schema, not in the tool, and it is noted on #10.2. A trust stage backed only by an unscoreable heuristic was being reported as EARNED.
aux.T02Contextual Trust depends solely onaux.H08. With H08 inapplicable the shortfall list came back empty, and empty read as success — so every v1 spec was silently earning contextual trust on zero evidence. A claim dressed as a finding, which is the exact failure this taxonomy exists to name.Stages now carry
assessable. An unassessable stage is never earned, and it stops the ladder the way a broken one does:Two regression tests pin it. No issue is raised against the product for an unassessable stage — it is the format's limit, not the agent's failing.
v0 is unchanged
Same fixtures, same scores, same evidence strings:
strong-spec100/A/advocacy,weak-spec4/F/none.meta.spec_versionrecords which format produced a report, since scores are not comparable across the two.Linked Issue
Closes #10.
Type
Migration note: no IDs renamed and no schema changed.
aux-auditgoes to 0.2.0 because whataux.H01,aux.H03,aux.H04,aux.H05,aux.H07andaux.H10measure under v1 differs from v0, so scores are not comparable across formats. v0 specs keep scoring identically to 0.1.x.Contribution bar — checklist
debateIssue first. — none; [debate] agent-spec v1: per-action mandate with enforced_by, replacing the autonomy label #10 settled the vocabulary before any of this.schemas/validate.pyPASSED,check-coverage.py12/12,yamllintclean,check:schemasclean, links resolve.New dependency
ajvfor real draft 2020-12 validation — the package had exactly one runtime dependency (yaml) and now has two.format: dateonshutdown.last_testedis implemented rather than ignored, so ajv stops logging that it is skipping a format on every run.Out of scope
trust_stagein the input. [debate] agent-spec v1: per-action mandate with enforced_by, replacing the autonomy label #10 asked whether an input format should carry the audit's own output, and if so whether the tool should report the gap between claimed and supported stage. The field is read into evidence but nothing acts on it yet. "You declare aux.T03; the spec supports aux.T01" is still the most useful line this tool could print.🤖 Generated with Claude Code
https://claude.ai/code/session_01MhpqWEvwKp7NrmJfdXYq4M
Generated by Claude Code